home *** CD-ROM | disk | FTP | other *** search
- /*
- * main.c - Initialization before main-loop and cleanup before exit.
- *
- * (C) 1994 Mikael Nordqvist (d91mn@efd.lth.se, mech@df.lth.se)
- */
-
- #include <stdio.h>
- #include <sys/types.h>
- #include <unistd.h>
- #include <stdlib.h>
- #include <fcntl.h>
- #include <sys/wait.h>
- #include <errno.h>
- #include <sys/soundcard.h>
- #include <sys/stat.h>
- #include <dirent.h>
- #include <termios.h>
- #include <signal.h>
- #include <string.h>
- #include <time.h>
-
- #include "mod.h"
-
- SEQ_DECLAREBUF();
- extern int seqfd, gus_dev;
- extern struct options default_opt;
- extern char quit;
-
- int total_time;
-
- struct mod_info M; /* The module */
- char workdir[PATH_MAX+1]; /* The directory mod was started from */
- int ack_pipe[2]; /* Player sends acks to main through this one */
- int player2main_synced[2]; /* Message from player to main (synced) */
- int main2player[2]; /* Message from main to player */
-
- pid_t pid_main, pid_player;
-
- int main(int argc, char *argv[])
- {
- struct termios tio, orig_tio;
- char tmp, day, hour, min, sec;
-
- srand(time((time_t)0)); /* Randomize */
- getcwd(workdir, PATH_MAX); /* Store working directory */
-
- if(!strcmp("mod_mklist", argv[0]))
- mklist(argc, argv); /* Must be after workdir is set */
-
- if(mkdir(TMP_DIR , 0777) && errno != EEXIST)
- error("Unable to create " TMP_DIR ".\n");
-
- chmod(TMP_DIR, 0777); /* This is needed as mode&umask is used in mkdir */
-
- if(argc >= 2 && !strncmp(argv[1], "-k", 2))
- kill_mod();
-
- /* Special case to allow help if mod is already running */
- if(argc >= 2 && !strncmp(argv[1], "-h", 2)) {
- print_helptext(argv[0]);
- exit(0);
- }
-
- init_sound(); /* Make sure audio-resources are available and grab them */
- init_options(argc, argv);
-
- pid_main=getpid();
-
- /* Create communication-pipes */
- if(pipe(player2main_synced) || pipe(main2player) || pipe(ack_pipe))
- error("Unable to create pipes.");
-
- /* Player should never block */
- fcntl(player2main_synced[PIPE_WRITE], F_SETFL, O_NONBLOCK);
-
- /* Set up terminal if verbose (turn off linebuffering and echo) */
- if(default_opt.verbose) {
- tcgetattr(STDIN_FILENO, &orig_tio);
- tio=orig_tio;
- tio.c_lflag&=~(ICANON|ECHO);
- tio.c_cc[VMIN]=1;
- tio.c_cc[VTIME]=0;
- tcsetattr(STDIN_FILENO, TCSADRAIN, &tio);
- }
- fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK); /* Never block on keyboard */
-
- if(default_opt.interactive) {
- init_screen(); /* This one changes signal-handlers ! */
- }
-
- /* Install signal handlers _after_ ncurses initscr() */
- pid_player=1; /* Make sure handlers know we are the main process */
- install_signalhandlers();
-
- cleanup_sound(); /* Free resources before entering main loop */
- zero_resources(); /* Make sure nothing undefined get free()'d */
- total_time=0;
-
- main_loop(); /* Do it! */
-
- /* Clean up */
- cleanup_options();
-
- if(default_opt.verbose)
- tcsetattr(STDIN_FILENO, TCSADRAIN, &orig_tio);
-
- if(default_opt.interactive)
- cleanup_screen();
-
- info("\n");
-
- chdir(TMP_DIR);
- chdir("..");
- my_removedir(TMP_DIR); /* Try to delete all garbage-files in TMP_DIR */
-
- if(!default_opt.quiet && total_time && quit != QUIT_SIGNAL) {
- day=total_time/(24*3600);
- hour=(total_time/3600)%24;
- min=(total_time/60)%60;
- sec=total_time%60;
-
- printf("Total time spent playing was ");
- tmp=0;
- if(day) {
- if(day == 1)
- printf("1 day, ");
- else
- printf("%d days, ", day);
- tmp=1;
- }
- if(tmp || hour) {
- if(hour == 1)
- printf("1 hour, ");
- else
- printf("%d hours, ", hour);
- tmp=1;
- }
- if(tmp || min) {
- if(min == 1)
- printf("1 minute and ");
- else
- printf("%d minutes and ", min);
- tmp=1;
- }
- if(sec == 1)
- printf("1 second.\n");
- else
- printf("%d seconds.\n", sec);
- }
- return 0;
- }
-
- /* Removes a directory (recursively) located in the _current directory_ */
-
- void my_removedir(char *name)
- {
- DIR *d;
- struct dirent *de;
- struct stat s;
-
- if(!chdir(name)) {
- if((d=opendir("."))) {
- while((de=readdir(d))) {
- if(strcmp(de->d_name, ".") && strcmp(de->d_name, "..") &&
- strcmp(de->d_name, "mod.pid")) {
- if(stat(de->d_name, &s))
- continue;
- chmod(de->d_name, 0777); /* a+rwx */
- if(S_ISDIR(s.st_mode)) {
- my_removedir(de->d_name);
- }
- else
- unlink(de->d_name);
- }
- }
- chmod("mod.pid", 0777); /* a+rwx */
- unlink("mod.pid"); /* Remove this one last if it exists.
- * Can't remember WHY I wait with that one...
- */
- closedir(d);
- }
- chdir("..");
- }
- rmdir(name); /* May or may not work depending on owner of dir */
- }
-
- void write_pid(pid_t p)
- {
- int fd;
- char buf[10];
-
- if((fd=open(TMP_DIR"/mod.pid", O_RDONLY)) != -1) {
- error("There is a copy of mod running in the background, try mod -k.\n");
- }
-
- if((fd=open(TMP_DIR"/mod.pid", O_CREAT|O_TRUNC|O_WRONLY, 0777)) == -1)
- error("Unable to write 'mod.pid'", errno);
- sprintf(buf, "%09d\n", p);
- write(fd, buf, 10);
- close(fd);
- chmod(TMP_DIR"/mod.pid", 0777);
- }
-
-
- void kill_mod(void)
- {
- int fd, p;
- char buf[10];
-
- if((fd=open(TMP_DIR"/mod.pid", O_RDONLY)) == -1)
- error("No copy of mod running in the background.\n");
-
- if(read(fd, buf, 12) != 10)
- error("Trouble reading 'mod.pid'.\n");
- close(fd);
- p=atoi(buf);
- if(kill(p, SIGTERM)) {
- if(errno == EPERM)
- error("You don't have permission to kill the running copy of"
- " 'mod'.\n");
- else if(errno == ESRCH) {
- if(!unlink(TMP_DIR"/mod.pid")) {
- printf("Stale lock removed.\n");
- exit(0);
- }
- else
- error("Unable to remove stale lock.");
- }
- else
- error("No copy of mod running in the background.\n");
- }
- printf("Killed.\n");
- exit(0);
- }
-
-
- /* Main-process: Set quit-flag, kill child.
- * Child-process: Terminate. Maybe we should kill() father also?
- */
-
- void handler_quit(int sig)
- {
- if(pid_player) {
- signal(sig, handler_quit);
- if(pid_player != 1) /* Before forking of the first child */
- kill(pid_player, sig);
- quit=QUIT_SIGNAL;
- }
- else {
- cleanup_sound();
- exit(0);
- }
- }
-
-
- void install_signalhandlers(void)
- {
- signal(SIGHUP, handler_quit);
- signal(SIGINT, handler_quit);
- signal(SIGQUIT, handler_quit);
- signal(SIGTERM, handler_quit);
- signal(SIGTSTP, SIG_IGN); /* Maybe support suspension ? */
- }
-